package thomas.javase.threads.queue;

import org.junit.Test;

import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;

/**
 * https://ifeve.com/juc-arrayblockingqueue/
 * java.util.concurrent.ArrayBlockingQueue 是一个线程安全的、基于数组、有界的、阻塞的、FIFO 队列。
 * 试图向已满队列中放入元素会导致操作受阻塞；试图从空队列中提取元素将导致类似阻塞。
 *
 * 此类基于 java.util.concurrent.locks.ReentrantLock 来实现线程安全，所以提供了 ReentrantLock 所能支持的公平性选择。
 * add(E e)：把 e 加到 BlockingQueue 里，即如果 BlockingQueue 可以容纳，则返回 true，否则报异常
 * offer(E e)：表示如果可能的话，将 e 加到 BlockingQueue 里，即如果 BlockingQueue 可以容纳，则返回 true，否则返回 false
 * put(E e)：把 e 加到 BlockingQueue 里，如果 BlockQueue 没有空间，则调用此方法的线程被阻断直到 BlockingQueue 里面有空间再继续
 * poll(time)：取走 BlockingQueue 里排在首位的对象，若不能立即取出，则可以等 time 参数规定的时间,取不到时返回 null
 * take()：取走 BlockingQueue 里排在首位的对象，若 BlockingQueue 为空，阻断进入等待状态直到 Blocking 有新的对象被加入为止
 * remainingCapacity()：剩余可用的大小。等于初始容量减去当前的 size
 */
public class ArrayBlockingQueueResearch {


    /**
     * 我新建了大小为3的队列，把这个队列传给生产者和消费者，它们公用这个队列，满的时候生产者阻塞，空的时候消费者阻塞，然后开启生产者和消费者进程。
     *
     * 运行结果：（每次不一样）
     * @param args
     */
    public static void main(String[] args) {

        BlockingQueue<Integer> blockingQueue = new ArrayBlockingQueue<Integer>(3,true);
        Producer producerPut = new Producer(blockingQueue);
        Consumer consumer = new Consumer(blockingQueue);

        new Thread(producerPut).start();
        new Thread(consumer).start();
    }

    /**
     * 取出来的元素0，1，2，因为3-19根本没有放到队列里面，
     * 黨queue 滿時, offer不会阻塞，会跳过插入。
     *
     * 这个和put不一样，put会一直等待，就是说程序会一直停留在blockingQueue.put那一句，
     * offer会跳过blockingQueue.offer那一句，而进入下一个while循环，这样实际插入队列的数字就会不连续了。
     */
    @Test
    public  void testOffer() throws Exception{
        BlockingQueue<Integer> blockingQueue = new ArrayBlockingQueue<Integer>(3,true);
        Consumer consumer = new Consumer(blockingQueue);
        ProducerOffer producerOffer = new ProducerOffer(blockingQueue);

        new Thread(producerOffer).start();

        Thread.sleep(1);

        new Thread(consumer).start();
    }

}
